package middleware

import (
	"fmt"
	"time"

	"github.com/emicklei/go-restful/v3"
	"github.com/infraboard/mcube/http/label"
	"github.com/infraboard/mcube/logger"
	"github.com/infraboard/mcube/logger/zap"

	"gitee.com/go-course/go8/projects/devcloud/maudit/apps/operate"
	"gitee.com/go-course/go8/projects/devcloud/maudit/client/rpc"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/token"
)

// 给服务端提供的RESTful接口的 认证与鉴权中间件
func NewHttpAuditor() (*HttpAudit, error) {
	return &HttpAudit{
		log: zap.L().Named("audit.http"),
		// 从全部变量获取
		client: rpc.C(),
	}, nil
}

// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction
// type FilterFunction func(*Request, *Response, *FilterChain)

type HttpAudit struct {
	log logger.Logger
	// 基于rpc客户端进行封装
	client *rpc.ClientSet
}

// 是否开启权限的控制, 交给中间件使用方去觉得
func (a *HttpAudit) GoRestfulAuditFunc(req *restful.Request, resp *restful.Response, next *restful.FilterChain) {
	// 请求拦截
	route := req.SelectedRoute()
	meta := route.Metadata()
	a.log.Debugf("route meta: %s", meta)

	// 获取用户身份信息, 认证中间件里 如果开启了认证，已经设置了tk对象到 请求上下文中 Attribute
	obj := req.Attribute("tk")

	var record *operate.OperateLog
	isAudit, ok := meta[label.Audit]
	// 有审计标签,并且开启了审计
	if ok && obj != nil && isAudit.(bool) {
		tk := obj.(token.Token)
		record = operate.NewOperateLog()
		record.Domain = tk.Domain
		record.Namespace = tk.Namespace
		record.Username = tk.Username
		record.UserAgent = req.Request.UserAgent()
		record.Time = time.Now().UnixMilli()
		record.Action = route.Operation()
		record.Detail = fmt.Sprintf("%s.%s", route.Method(), route.Path())
		record.Request = req.Request.URL.String()
		a.client.Operate().SaveOperateLog(req.Request.Context(), record)
	}

	// next flow
	next.ProcessFilter(req, resp)

	// 如果需要记录响应需要在这里记录响应
	// 有审计标签,并且开启了审计
	if ok && obj != nil && isAudit.(bool) && record != nil {
		record.Response = ""
	}

	if record != nil {
		a.log.Debugf("save audit log")
		a.client.Operate().SaveOperateLog(req.Request.Context(), record)
	}
}
